import datetime

from fastapi import FastAPI
import uvicorn
from typing import Optional
from pydantic import BaseModel
from fastapi import Query, Body, status
from pydantic import validator, Field
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
import pydantic
from pydantic import BaseModel, Field

from fastapi import Depends

app = FastAPI()


class PageLimitParamModel(BaseModel):
    page: Optional[int]
    size: int = Query(..., embed=True)
    name: str = Query(...)


class BaseField:
    page = Field(1, ge=1)


class PageLimitParamModelPydantic(BaseModel):  # 这种模式都是json请求
    page: Optional[int]  # 这里虽然是写了Optional 但是没有赋值, 要求这个值可以不传递，如果不写Optional并且没有赋值，那么必须传递
    size: datetime.datetime = Field(default_factory=datetime.datetime.now)
    name: str = 'baloneo'  # 不写Optional 但是因为有值 所以可以不传递
    page2: Optional[int] = BaseField.page
    ok: Optional[bool] = False


class PageLimitParamModel2(object):
    def __init__(self, page: Optional[int] = 1, size1: str = Body('ss'), size2: str = Body('ss'), name: str = Query('Tom')):
        self.page = page
        self.size1 = size1
        self.size2 = size2
        self.name = name


class PageLimitParamModel3(object):
    def __init__(self, page: Optional[int] = 1, size1: str = Body('ss'), name: str = Query('Tom')):
        self.page = page
        self.size1 = size1
        self.name = name


"""
common: Model这种模式的都是从json body里获取
如果json要求传递的参数只有一个，那么一般要加上 embed=True，因为如果body json参数只有一个，会认为整个body就是value
如果要把请求参数封装在Depends，那么只能使用普通类__init__(Body(), Query())的模式

def hello(common: pydantic.BaseModel = Depends()) 这种语法没有错误，但是逻辑错误，因为Depends读取的是class的__init__的参数
这样书写会导致失效
"""

# http get ':9999/test1'
# http get ':9999/test1?age1=1' age2=2
# http get ':9999/test1?age1=1' age1=99 age2=4 common:='{"size": 10}'
@app.get('/test1')
async def test1(common: PageLimitParamModel, age1: int = Query(...), age2: int = Body(...)):
    return {'page': common.page, 'size': common.size, 'name': common.name, 'age1': age1, 'age2': age2}


# http get ':9999/test11?age1=1' age1=99 common:='{"size": 10}' # error
# http get ':9999/test11?age1=1' size=111
@app.get('/test11')
async def test11(common: PageLimitParamModel, age1: int = Query(...)):
    return {'page': common.page, 'size': common.size, 'name': common.name, 'age1': age1}


# http get ':9999/test2'
@app.get('/test2')
async def test2(common: PageLimitParamModel = Depends()):
    return {'page': common.page, 'size': common.size, 'name': common.name}


# http post ':9999/test3'
@app.post('/test3')
async def test3(common: PageLimitParamModel3 = Depends()):
    return {'page': common.page, 'size': [common.size1, common.size1], 'name': common.name}


# http post ':9999/test3'
@app.post('/d')
async def d(common: PageLimitParamModelPydantic):
    print(common)
    return common


if __name__ == '__main__':
    uvicorn.run('__main__:app', port=9999, reload=True)

